/*
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#if !defined(RSS_MANAGER_H)
#define RSS_MANAGER_H

#include "..\client\Util.h"
#include "..\client\Singleton.h"
#include "..\client\Speaker.h"
#include "..\client\Semaphore.h"
#include "..\client\TimerManager.h"
#include "..\client\SettingsManager.h"

class RSSItem
{
	typedef RSSItem* Ptr;
public:
	RSSItem(string const& aTitle, string const& aUrl, string const& aDesc, time_t aPublishDate,
            string const& aAuthor, string const& aCategory, string const& aSource) : 
		title(aTitle), url(aUrl), desc(aDesc), publishDate(aPublishDate), author(aAuthor), category(aCategory), source(aSource)
	{
	}

    RSSItem(const RSSItem* src):
		title(src->getTitle()), url(src->getUrl()), desc(src->getDesc()), publishDate(src->getPublishDate()), author(src->getAuthor()), category(src->getCategory()), source(src->getSource())
    {
        
    }
    
    GETSET(string, title, Title);
	GETSET(string, url, Url);
	GETSET(string, desc, Desc);
	GETSET(time_t, publishDate, PublishDate);
	GETSET(string, author, Author);
	GETSET(string, category, Category);
	GETSET(string, source, Source);

};

class RSSFeed {
public:
    RSSFeed(string const& afeedURL, string const& aSource, string const& codeingType)
        : feedURL(afeedURL), source(aSource), lastNewsDate(0), codeing(codeingType)
    {}
    virtual ~RSSFeed();

    typedef vector<RSSItem*> RSSItemList;
	typedef RSSItemList::const_iterator RSSItemIter;

    bool UpdateFeed();
    bool UpdateFeedNewXML();

	string ConvertFromHTML(string const &htmlString);
	string ConvertFromHTMLSymbol(string const &htmlString, string const& findString, string const& changeString);

    const RSSItemList& lockList() { cs.lock(); return m_newsList; }
	void unlockList() { cs.unlock(); }

    GETSET(time_t, lastNewsDate, LastNewsDate);
    GETSET(string, feedURL, FeedURL);
	GETSET(string, source, Source);
	GETSET(string, codeing, Codeing);

private:
    size_t GetData(string const & url, string& data);
    void clearList();
    void removeCDATA(string const & str, string &tmp);
	bool UpdateFeedOldParser(const string& data);
    CriticalSection cs;

    RSSItemList m_newsList;
};

class RSSListener {
public:
	virtual ~RSSListener() { }
	template<int I>	struct X { enum { TYPE = I };  };

	typedef X<0> Added;
	typedef X<1> NewRSS;
	typedef X<2> Failed;

    virtual void on(Added, RSSItem*) throw() { }
    virtual void on(Failed, const string&) throw() { }
    virtual void on(NewRSS, const int& ) throw () { }
}; 

class RSSManager : 
    public Singleton<RSSManager>, public Speaker<RSSListener>, public Thread, private SettingsManagerListener, private TimerManagerListener
{
public:

    typedef vector<RSSItem*> NewsList;
	typedef NewsList::const_iterator NewsIter;   


    typedef vector<RSSFeed*> FeedList;
    typedef FeedList::const_iterator FeedIter;
    
    bool UpdateFeeds();

    const FeedList& lockFeedList() { cs.lock(); return m_feeds; }
	void unlockFeedList() { cs.unlock(); }

    const NewsList& lockNewsList() { csNews.lock(); return m_newsList; }
	void unlockNewsList() { csNews.unlock(); }

    bool hasRSSFeed(string const & url, string const& name);
    void shutdown();

	RSSFeed* addNewFeed(string const& url, string const& name, string const& codeing, bool bUpdateFeeds = false);
	bool removeFeedAt(size_t pos);

    typedef vector<string> CodeingList;
	typedef CodeingList::const_iterator CodeingIter;

	string GetCodeing(size_t i) { if ( i>=m_codeingList.size()) return ""; return m_codeingList[i]; }

	size_t GetCodeingByString(string const& codeing);

private:


	CodeingList m_codeingList;

    enum Tasks {
		CHECK_NEWS,
        SHUTDOWN
	};

    struct TaskData { 
		virtual ~TaskData() throw() { }
	};

	friend class Singleton<RSSManager>;

	RSSManager();

	virtual ~RSSManager() throw();

    void clearLists();

    int run();

    FeedList m_feeds;

    NewsList m_newsList;

    CriticalSection cs;
    CriticalSection csNews;

    Semaphore taskSem;

	list<pair<Tasks, TaskData*> > m_tasks;
	bool failed;
	
	void fail(const string& aError);	
	bool checkEvents();

	void addTask(Tasks task, TaskData* data) 
	{
	     m_tasks.push_back(make_pair(task, data)); 
		 taskSem.signal(); 
	}
    void updateAllFeeds();

	bool canAdd(RSSItem* item);

    // SettingsManagerListener
	virtual void on(SettingsManagerListener::Save, SimpleXML& xml) throw() {
		save(xml);
	}
	virtual void on(SettingsManagerListener::Load, SimpleXML& xml) throw() {
		load(xml);
	}
	
	// TimerManagerListener
	virtual void on(TimerManagerListener::Minute, uint64_t aTick) throw();
	void load(SimpleXML& aXml);
	void save(SimpleXML& aXml);
	unsigned int minuteCounter;
    
    // Show ballon
    void ShowBallonNews();


};
#endif // !defined(RSS_MANAGER_H)

/**
 * @file
 * $Id: RSSManager.h 7912 2011-08-16 17:41:35Z pavel.pimenov $
 */
